/* Project for a stick hockey table scoreboard with
 * automatic goal detection and notification and sound.
 * Used PIC16F688 device. */

#include <stdio.h>
#include <stdlib.h>
#include <pic.h>
#include "timing.h"
#include "MAX7219.h"                                  // MAX7219 header file

#define AWAY_BTN     RC3  //bit 3 of PORTC
#define HOME_BTN     RC4  //bit 4 of PORTC
#define START_BTN    RC5  //bit 5 of PORTC


__CONFIG(INTIO & WDTDIS & PWRTDIS & MCLRDIS & UNPROTECT & BORDIS & IESODIS & FCMDIS);	
 
unsigned char game_time_in_minutes_tens;  
unsigned char game_time_in_minutes_ones;  
unsigned char game_time_in_secs_tens;  
unsigned char game_time_in_secs_ones;
unsigned char home_score_tens;
unsigned char home_score_ones;
unsigned char away_score_tens;
unsigned char away_score_ones;

void displayTime(void){
	//convert from number value to ascii value (just add 48 decimal to the number to get the ASCII number equivalent)
	
	MAX7219_DisplayChar(1, game_time_in_minutes_tens + 48);  
	MAX7219_DisplayChar(2, game_time_in_minutes_ones + 48);
	MAX7219_DisplayChar(3, game_time_in_secs_tens + 48); 
	MAX7219_DisplayChar(4, game_time_in_secs_ones + 48); 
}

void displayScore(void){
	//convert from number value to ascii value (just add 48 decimal to the number to get the ASCII number equivalent)

	MAX7219_DisplayChar(7, home_score_tens + 48); 
	MAX7219_DisplayChar(8, home_score_ones + 48);
	MAX7219_DisplayChar(5, away_score_tens + 48); 
	MAX7219_DisplayChar(6, away_score_ones + 48); 
}

void blinkDigits(char digitsselect){
	//0 blinks left side score, 1 blinks right side score, 2 blinks both scores, anything else blinks time
	//convert from number value to ascii value (just add 48 decimal to the number to get the ASCII number equivalent)

	unsigned char blinkrate = 500; //must be less than 999
	unsigned char blinknum = 10; //number of times to blink
	unsigned char loopcnt = 0;

	switch(digitsselect)
	{
		case 0:	
			for (loopcnt = 0; loopcnt < blinknum; loopcnt++)                  
			{
				delayMs(blinkrate);
				MAX7219_DisplayChar(7, ' '); 
				MAX7219_DisplayChar(8, ' ');
				delayMs(blinkrate);
				MAX7219_DisplayChar(7, home_score_tens + 48); 
				MAX7219_DisplayChar(8, home_score_ones + 48);	
			}
			break;
		case 1:
			for (loopcnt = 0; loopcnt < blinknum; loopcnt++)                  
			{
				delayMs(blinkrate);
				MAX7219_DisplayChar(5, ' '); 
				MAX7219_DisplayChar(6, ' ');
				delayMs(blinkrate);
				MAX7219_DisplayChar(5, away_score_tens + 48); 
				MAX7219_DisplayChar(6, away_score_ones + 48);
			}
			break;
		case 2:
			for (loopcnt = 0; loopcnt < blinknum; loopcnt++)                  
			{
				delayMs(blinkrate);
				MAX7219_DisplayChar(7, ' '); 
				MAX7219_DisplayChar(8, ' ');
				MAX7219_DisplayChar(5, ' '); 
				MAX7219_DisplayChar(6, ' ');
				delayMs(blinkrate);
				MAX7219_DisplayChar(7, home_score_tens + 48); 
				MAX7219_DisplayChar(8, home_score_ones + 48);
				MAX7219_DisplayChar(5, away_score_tens + 48); 
				MAX7219_DisplayChar(6, away_score_ones + 48);			
			}
			break;
		default:
			for (loopcnt = 0; loopcnt < blinknum; loopcnt++)                  
			{
				delayMs(blinkrate);
				MAX7219_DisplayChar(1, ' '); 
				MAX7219_DisplayChar(2, ' ');
				MAX7219_DisplayChar(3, ' '); 
				MAX7219_DisplayChar(4, ' ');
				delayMs(blinkrate);
				MAX7219_DisplayChar(1, game_time_in_minutes_tens + 48); 
				MAX7219_DisplayChar(2, game_time_in_minutes_ones + 48);
				MAX7219_DisplayChar(3, game_time_in_secs_tens + 48); 
				MAX7219_DisplayChar(4, game_time_in_secs_ones + 48); 				
			}
			break;
	} // end switch
}

void config_io(void){

	TRISA2 = 0; //speaker output  
	
	MAX7219_Init();	//TRISC0-2 are configed in MAX7219 code

	TRISC3 = 1; // Away scored button input
	TRISC4 = 1; // Home scored button input
	TRISC5 = 1; // Start button input 

	//comparator settings for all comparator pins are 1's when configured as digital.
	//comparator pins are 0's when configured as analog.
	CM0 = 1;  
	CM1 = 1;
	CM2 = 1;

	//analog input settings
	ANS2 = 0; //speaker output
	ANS7 = 0; //Away scored button input
}


char checkButtons(char buttoncheck){
	char returnval = 0;

	switch(buttoncheck)
	{
		case 0:	//start button
			if(START_BTN == 1)
			{
				delayMs(2); //debounce time
				if(START_BTN == 1) 
				{
					returnval = 1;
				}
				else
				{
					returnval = 0;
				}	
			}
			break;
	
		case 1:  //home scored button
			if(HOME_BTN == 1)
			{
				delayMs(2); //debounce time
				if(HOME_BTN == 1) 
				{
					returnval = 1;
				}
				else
				{
					returnval = 0;
				}
			}	
			break;
		case 2:	//visitor scored button
			if(AWAY_BTN == 1)
			{
				delayMs(2); //debounce time
				if(AWAY_BTN == 1) 
				{
					returnval = 1;
				}
				else
				{
					returnval = 0;
				}
			}		
			break;
		default:
			break;
	} //end switch

	return returnval;
}

void main(void){

	unsigned char home_score;
	unsigned char away_score;

	init_interrupts();
	config_io();
	
	restart_lbl:

	MAX7219_DisplayChar(1, 'H');
	MAX7219_DisplayChar(2, 'E');
	MAX7219_DisplayChar(3, 'L');
	MAX7219_DisplayChar(4, '0');

	//wait for start button to be pressed		
	while (checkButtons(0) == 0)
	{
		continue;
	}


	genFreqSecs(500, 5); //startup sound for 5 seconds

	countdownseconds = MAXCNTDWNSECS; 

	//begin 10 minute game countdown timer and reset the scores.
	game_time_in_secs  = GAME_DUR_MINS * 60;
	home_score = 0;
	away_score = 0;
	newSecond = newmillisecond = 0;
	gameplaying = 1;
	 	
	//wait for timer to expire while keeping score
	while(game_time_in_secs >= 0){
		
		//display scoreboard
		game_time_in_minutes_tens = game_time_in_secs / 60 / 10;  
		game_time_in_minutes_ones = game_time_in_secs / 60 - game_time_in_minutes_tens * 10;  		
		game_time_in_secs_tens = (game_time_in_secs - (game_time_in_minutes_tens * 10 + game_time_in_minutes_ones) * 60) / 10;  
		game_time_in_secs_ones = (game_time_in_secs - (game_time_in_minutes_tens * 10 + game_time_in_minutes_ones) * 60) - game_time_in_secs_tens * 10;
		 
		home_score_tens = home_score / 10;
		home_score_ones = home_score - home_score_tens * 10;
		away_score_tens = away_score / 10;
		away_score_ones = away_score - away_score_tens * 10;
	
		//if start button was pressed  here then pause the timer.
		if (checkButtons(0) == 1)
		{		
			genFreqSecs(500, 1); //sound a short buzz to notify that timer is paused.
			gameplaying = 0;
			while (checkButtons(0) == 0)
			{
				continue;
			}
			gameplaying = 1;
			genFreqSecs(500, 1); //sound a short buzz to nofify that pause is over
		}

		//check Away goal	
		if (checkButtons(2))
		{
			gameplaying = 0;
			//record the goal for the RW team!
			//play the score alert through the speaker
			away_score++;			
			genFreqSecs(700, 3); //generate sound for 3 seconds
			gameplaying = 1;				 	 
		}
	
		//check Home goal
		if (checkButtons(1))
		{
			gameplaying = 0;
			//record the goal for the AV team!
			//play the score alert through the speaker
			home_score++;				
		    genFreqSecs(600, 3); //generate sound for 3 seconds								
			gameplaying = 1;					 
		}					
		
		displayTime();	
		displayScore();
	}	 

	//GAME OVER - SOUND THE HORN AND LEAVE THE SCORE DISPLAYED 
	gameplaying = 0; //game timer over
	genFreqSecs(450, 5); //generate sound for 8 seconds	

	if(home_score > away_score)
	{
		blinkDigits(0);
	}
	else if(away_score > home_score)
	{	
		blinkDigits(1);
	}

	if(away_score == home_score)
	{
		blinkDigits(2);
		//wait for Goal
	
		game_time_in_minutes_tens = 0;  
		game_time_in_minutes_ones = 0;  
		game_time_in_secs_tens = 0;  
		game_time_in_secs_ones = 0;
		displayTime();

		while(away_score == home_score)
		{
			//check for Away goal	
			if (checkButtons(2))
			{
				//play the score alert through the speaker
				away_score++;
				genFreqSecs(700, 3); //generate sound for 3 seconds
				blinkDigits(1);					
			}
	
			//check for Home goal
			if (checkButtons(1))
			{
				//play the score alert through the speaker
				home_score++;			
				genFreqSecs(600, 3); //generate sound for 3 seconds					
				blinkDigits(0);												
			}
		} //end while
	} //end if
	
	displayScore();
	genFreqSecs(400, 5); //generate sound for 5 seconds	
    MAX7219_Clear();  
	goto restart_lbl;
}



